package org.moyrax.compressor;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.shared.model.fileset.util.FileSetManager;

/**
 * Creates a bundle file which contains a set of sources in a single file.
 *
 * @goal bundle
 * @phase process-test-resources
 *
 * @author Matias Mirabelli <lumen.night@gmail.com>
 */
public class BundlePlugin extends AbstractMojo {
  /**
   * Source files to be written to the bundle.
   *
   * @parameter
   * @required
   */
  private List bundles;

  /**
   * Object to ask the files specified in the plugin configuration.
   */
  private final FileSetManager fileSetManager = new FileSetManager();

  /**
   * Executes this plugin.
   */
  public void execute() throws MojoExecutionException {
    try {
      Iterator i = bundles.iterator();

      while (i.hasNext()) {
        final Bundle bundle = (Bundle)i.next();

        String[] includes = fileSetManager.getIncludedFiles(bundle.files);

        this.checkOutputFile(bundle.outputFile);
        this.createBundle(includes, bundle.files.getDirectory(),
            bundle.outputFile, bundle.compress);
      }
    } catch (Exception e) {
      throw new MojoExecutionException("Plugin exception.", e);
    }
  }

  /**
   * Creates the bundle file in the configured location.
   *
   * @param includes    Files to be added in the bundle.
   * @param directory   Directory from the files should be readed.
   * @param outputFile  Bundle file.
   */
  private void createBundle (final String[] includes, final String directory,
      final File outputFile, Boolean compress) {
    try {
      final FileWriter writer = new FileWriter(outputFile);

      for (int i = 0; i < includes.length; i++) {
        File file = new File(directory + "/" + includes[i]);

        writer.write(this.readFile(file));
      }

      writer.close();

      if (compress != null && compress.booleanValue()) {
        this.compressFile(outputFile);
      }
    } catch (IOException ex) {
      throw new CompressorException("Error proccessing file.", ex);
    }
  }

  /**
   * Read a whole file and returns its content.
   *
   * @param inputFile  File to read.
   */
  private String readFile(final File inputFile) throws IOException {
    final BufferedReader reader = new BufferedReader(new FileReader(inputFile));
    final StringBuffer builder = new StringBuffer();

    String line = reader.readLine();

    while (line != null) {
      builder.append(line);
      builder.append("\n");

      line = reader.readLine();
    }

    return builder.toString();
  }

  /**
   * Checks if the output directory and file exists.
   */
  private void checkOutputFile(File outputFile) {
    File directory = new File(outputFile.getPath());

    if (!directory.exists()) {
      directory.mkdirs();
    }

    if (outputFile.exists()) {
      outputFile.delete();
    }
  }

  /**
   * Compress the specified file using the default compressor and compression
   * options.
   *
   * @param file  File to be compressed.
   */
  private void compressFile(final File file) {
    final DefaultCompressor compressor = new DefaultCompressor();

    /* The compressed result is saved to the same file. */
    compressor.munge = true;
    compressor.compress(file, file);
  }
}
